using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using WindowServices.Server.Interface;
using WindowServices.Common.Properties;

namespace WindowServices.Common
{
    public class ServiceConfig : IDisposable
    {
        public ServiceConfig()
        {
        }

        public ServiceConfig(string configFile)
        {
            if (!string.IsNullOrEmpty(configFile))
            {
                _configfile = configFile;
            }
        }

        private readonly string _configfile = string.Format("{0}\\ServiceList.config", AppDomain.CurrentDomain.BaseDirectory.TrimEnd('\\'));
        private const string RootPath = "/configuration/Services";

        private const string ServicePath = RootPath + "/Service";

        public List<ServiceEntityEx> GetAllServiceEntity()
        {
            return GetServiceEntity(Guid.Empty, null);
        }

        public void AddServiceEntity(ServiceEntityEx se)
        {
            using (ConfigHelper helper = CreateConfigHelper())
            {
                AddServiceEntity(helper, se);
                helper.Save();
            }
        }

        public void AddServiceEntity(List<ServiceEntityEx> list)
        {
            using (ConfigHelper helper = CreateConfigHelper())
            {
                list.ForEach(se =>AddServiceEntity(helper, se));
                helper.Save();
            }
        }

        public void DelServiceEntity(List<ServiceEntityEx> list)
        {
            using (ConfigHelper helper = CreateConfigHelper())
            {
                DelServiceEntity(helper, list);
                helper.Save();
            }
        }

        private void DelServiceEntity(ConfigHelper helper, IEnumerable<ServiceEntityEx> list)
        {
            foreach (var se in list)
            {
                DelServiceEntity(helper, se.Id, se.Version);
            }
        }

        private void DelServiceEntity(ConfigHelper helper, Guid id, Version version)
        {
            helper.DelNode(version != null
                ? string.Format("{0}[@id=\"{1}\" and @version=\"{2}\"]", ServicePath, id, version)
                : string.Format("{0}[@id=\"{1}\"]", ServicePath, id));
        }

        public void DelServiceEntity(Guid id, Version version)
        {
            using (ConfigHelper helper = CreateConfigHelper())
            {
                DelServiceEntity(helper, id, version);
                helper.Save();
            }
        }

        public void UpdateServiceEntity(ServiceEntityEx se)
        {
            using (var helper = CreateConfigHelper())
            {
                DelServiceEntity(helper, se.Id, se.Version);
                AddServiceEntity(helper, se);
                helper.Save();
            }
        }

        public List<ServiceEntityEx> GetServiceEntity(Guid id, Version version)
        {
            var list = new List<ServiceEntityEx>();

            string xpath;

            if (id == Guid.Empty)
            {
                xpath = ServicePath;
            }
            else
            {
                xpath = version != null ? string.Format("{0}[@id=\"{1}\" and & @version=\"{2}\"]", ServicePath, id, version) : string.Format("{0}[@id=\"{1}\"]", ServicePath, id);
            }

            var isRead = false;
            var count = 0;
            while (!isRead && count < 5)
            {
                try
                {
                    using (ConfigHelper helper = CreateConfigHelper())
                    {
                        var list1 = helper.GetXmlNodeList(xpath);
                        foreach (var node in
                            list1.Cast<XmlNode>().Where(node => String.Compare("service", node.Name, StringComparison.OrdinalIgnoreCase) == 0))
                        {
                            var se = new ServiceEntityEx
                            {
                                State = ServiceState.None,
                                Id = new Guid(node.Attributes["id"].Value),
                                Name = node.Attributes["name"].Value,
                                Type = node.Attributes["type"].Value,
                                Version = new Version(node.Attributes["version"].Value),
                                IsEdit = String.Compare("true", node.Attributes["edit"].Value, StringComparison.OrdinalIgnoreCase) == 0,
                                Inheritance =
                                    String.Compare("true", node.Attributes["inheritance"].Value, StringComparison.OrdinalIgnoreCase) == 0,
                                UserInfo = new User()
                            };

                            if (!se.Inheritance)
                            {
                                #region user

                                foreach (var child in
                                    node.ChildNodes.Cast<XmlNode>().Where(
                                        child => String.Compare(child.Name, "inheritance", StringComparison.OrdinalIgnoreCase) == 0))
                                {
                                    switch (child.Name.ToLower())
                                    {
                                        case "domain":
                                            se.UserInfo.Domain = GetAttributeValue(child.Attributes, "domain");
                                            break;
                                        case "userid":
                                            se.UserInfo.UserId = GetAttributeValue(child.Attributes, "userid");
                                            break;
                                        case "password":
                                            se.UserInfo.PassWord = GetAttributeValue(child.Attributes, "password");
                                            break;
                                    }
                                }

                                #endregion
                            }

                            list.Add(se);
                        }

                        isRead = true;
                    }
                }
                catch (IOException ee)
                {
                    isRead = false;
                    count++;
                    LogHelper.WriteEntityConfigError(string.Format(Resources.ReReadServiceConfig, ee, count), EventType.WriteconfigError);
                }
                catch (Exception ee)
                {
                    LogHelper.WriteEntityConfigError(ee.ToString(), EventType.WriteconfigError);
                    list = null;
                    isRead = true;
                }
            }

            return list;
        }

        private string GetAttributeValue(XmlAttributeCollection collection, string name)
        {
            if (collection == null)
            {
                return "";
            }

            if (collection.Count == 0)
            {
                return "";
            }

            return collection[name] == null ? "" : collection[name].Value;
        }

        private void AddServiceEntity(ConfigHelper helper, ServiceEntityEx se)
        {
            var dicProperty = new Dictionary<string, string>
                                  {
                                      {"id", se.Id.ToString()},
                                      {"name", se.Name},
                                      {"type", se.Type},
                                      {"version", se.Version.ToString()},
                                      {"edit", se.IsEdit.ToString()},
                                      {"inheritance", se.Inheritance.ToString()}
                                  };


            helper.AddNode(RootPath, "Service", dicProperty, null);

            var node = helper.GetSignleXmlNode(string.Format("{0}[@id=\"{1}\" and @version=\"{2}\"]", ServicePath, se.Id, se.Version));

            dicProperty.Clear();

            if (se.Inheritance)
            {
                dicProperty.Add("domain", "");
                dicProperty.Add("userid", "");
                dicProperty.Add("password", "");
            }
            else
            {
                dicProperty.Add("domain", se.UserInfo.Domain);
                dicProperty.Add("userid", se.UserInfo.UserId);
                dicProperty.Add("password", se.UserInfo.PassWord);
            }

            helper.AddNode(node, "Inheritance", dicProperty, null);

        }

        private ConfigHelper CreateConfigHelper()
        {
            return new ConfigHelper(_configfile);
        }

        public void Dispose()
        {
        }
    }

    public class TempServiceConfig : ServiceConfig
    {
        public static readonly string ConfigFile = string.Format("{0}\\TempServiceList.config",
                                                           AppDomain.CurrentDomain.BaseDirectory.TrimEnd('\\'));
        public TempServiceConfig(bool deleteFile)
            : base(ConfigFile)
        {
            if (!deleteFile)
            {
                return;
            }
            if (File.Exists(ConfigFile))
            {
                File.Delete(ConfigFile);
            }

            File.Copy(ConfigFile + ".Template", ConfigFile);
        }


    }
}